﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace System
{
    /// <summary>
    /// Enumerable extension meth
    /// </summary>
    public static class EnumerableExt
    {
        /// <summary>
        /// Converts value to string.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="separator">The separator.</param>
        /// <returns></returns>
        public static string AsString(this IEnumerable value, string separator = ", ")
        {
            if (value.IsNull())
                return string.Empty;
            if (value is string)
                return (string)value;
            if (value is byte[])
                return ((byte[])value).ByteArrayToString();
            StringBuilder str = new StringBuilder();
            foreach (object obj in value)
            {
                if(str.Length>0)
                    str.Append(separator);
                str.Append(obj.AsString());
            }
            return str.ToString();
        }

        /// <summary>
        /// Determines whether list contains specified item.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="item">The item.</param>
        /// <returns></returns>
        public static bool ContainsIgnoreCase(this List<string> value, string item)
        {
            if (value == null)
                return false;
            return value.Contains(item, StringComparer.OrdinalIgnoreCase);
        }

        /// <summary>
        ///Returns sum of items from list. Each item is in new line
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static string ToMultiLineString(this List<string> value)
        {
            StringBuilder str = new StringBuilder();
            foreach (string s in value)
                str.AppendLine(s);
            return str.ToString();
        }

        /// <summary>
        /// Adds value to the list, if not exist.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list">The list.</param>
        /// <param name="value">The value.</param>
        public static void AddIfNotExist<T>(this List<T> list, T value)
        {
            if (!list.Contains(value))
            {
                list.Add(value);
            }
        }

        /// <summary>
        /// Returns combinations of the specified elements.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="elements">The elements.</param>
        /// <param name="k">The k.</param>
        /// <returns></returns>
        public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k)
        {
            return k == 0 ? new[] { new T[0] } :
              elements.SelectMany((e, i) =>
                elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] { e }).Concat(c)));
        }

        /// <summary>
        /// Splits list to multiple lists. Each list can have maximum size of maxItems
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list">The list.</param>
        /// <param name="maxItems">The maximum items.</param>
        /// <returns></returns>
        public static List<List<T>> SplitByListSize<T>(this List<T> list, int maxItems)
        {
            List<List<T>> retVal = new List<List<T>>();
            if (maxItems > 0)
            {
                int start = 0;
                while (start < list.Count)
                {
                    int count = list.Count - start > maxItems ? maxItems : list.Count - start;
                    retVal.Add(list.GetRange(start, count));
                    start += maxItems;
                }
            }
            return retVal;
        }

        /// <summary>
        /// Splits the by list to maximum maxLists lists
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list">The list.</param>
        /// <param name="maxLists">The maximum lists.</param>
        /// <returns></returns>
        public static List<List<T>> SplitByListCount<T>(this List<T> list, int maxLists)
        {
            List<List<T>> retVal = new List<List<T>>();
            if (maxLists > 0)
            {
                int maxItems = list.Count / maxLists;
                if (maxItems * maxLists < list.Count)
                    maxItems++;
                retVal = list.SplitByListSize(maxItems);
            }
            return retVal;
        }

        /// <summary>
        /// Moves first ocurence of specified item to specified index
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list">List</param>
        /// <param name="item">Item</param>
        /// <param name="index">Index</param>
        /// <returns><c>true</c> if item was moved, <c>false</c> if list is null, item is not in tne list or index is out of range</returns>
        public static bool MoveItem<T>(this List<T> list, T item, int index)
        {
            if (list != null)
            {
                if (list.Contains(item))
                {
                    if (index>-1 && list.Count >= index)
                    {
                        list.Remove(item);
                        list.Insert(index, item);
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Moves the item from one index to other
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list">The list.</param>
        /// <param name="fromIndex">From index.</param>
        /// <param name="toIndex">To index.</param>
        /// <returns></returns>
        public static bool MoveItem<T>(this List<T> list, int fromIndex, int toIndex)
        {
            if (list != null)
            {
                if (fromIndex > -1 && list.Count >= fromIndex &&
                    toIndex > -1 && list.Count >= toIndex)
                {
                    T item = list[fromIndex];
                    list.RemoveAt(fromIndex);
                    list.Insert(toIndex, item);
                    return true;
                }
            }
            return false;
        }
    }
}
